Welcome Guest | Sign in | Register
The C Basics - C Programming Interview Questions and Answers | LucentBlackBoard | LucentBlackBoard.com

Home > Technical Interviews > Computer Science & Engineering > C Programming > The C Basics Questions and Answers

6. Other than in a for statement, when is the comma operator used?

The comma operator is commonly used to separate variable declarations, function arguments, and expressions, as well as the elements of a for statement. Look closely at the following program, which shows some of the many ways a comma can be used:
#include
#include
void main(void);
void main()
{
/* Here, the comma operator is used to separate
three variable declarations. */
int i, j, k;
/* Notice how you can use the comma operator to perform
multiple initializations on the same line. */
i = 0, j = 1, k = 2;
printf("i = %d, j = %d, k = %d\n", i, j, k);
/* Here, the comma operator is used to execute three expressions
in one line: assign k to i, increment j, and increment k.
The value that i receives is always the rightmost expression. */
i = (j++, k++);
printf("i = %d, j = %d, k = %d\n", i, j, k);
/* Here, the while statement uses the comma operator to
assign the value of i as well as test it. */
while (i = (rand() % 100), i != 50)
printf("i is %d, trying again...\n", i);
printf("\nGuess what? i is 50!\n");
}
Notice the line that reads
i = (j++, k++);
This line actually performs three actions at once. These are the three actions, in order:
1. Assigns the value of k to i. This happens because the left value (lvalue) always evaluates to the rightmost argument. In this case, it evaluates to k. Notice that it does not evaluate to k++, because k++ is a postfix incremental expression, and k is not incremented until the assignment of k to i is made. If the expression had read ++k, the value of ++k would be assigned to i because it is a prefix incremental expression, and it is incremented before the assignment is made.
2. Increments j.
3. Increments k.
Also, notice the strange-looking while statement:
while (i = (rand() % 100), i != 50)
printf("i is %d, trying again...\n");
Here, the comma operator separates two expressions, each of which is evaluated for each iteration of the whilestatement. The first expression, to the left of the comma, assigns i to a random number from 0 to 99.
The second expression, which is more commonly found in a while statement, is a conditional expression that tests to see whether i is not equal to 50. For each iteration of the while statement, i is assigned a new random number, and the value of i is checked to see that it is not 50. Eventually, i is randomly assigned the value 50, and the while statement terminates.

7. How can you tell whether a loop ended prematurely?

Generally, loops are dependent on one or more variables. Your program can check those variables outside the loop to ensure that the loop executed properly. For instance, consider the following example:
#define REQUESTED_BLOCKS 512
int x;
char* cp[REQUESTED_BLOCKS];
/* Attempt (in vain, I must add...) to
allocate 512 10KB blocks in memory. */
for (x=0; x< REQUESTED_BLOCKS; x++)
{
cp[x] = (char*) malloc(10000, 1);
if (cp[x] == (char*) NULL)
break;
}
/* If x is less than REQUESTED_BLOCKS,
the loop has ended prematurely. */
if (x < REQUESTED_BLOCKS)
printf("Bummer! My loop ended prematurely!\n");
Notice that for the loop to execute successfully, it would have had to iterate through 512 times. Immediately following the loop, this condition is tested to see whether the loop ended prematurely. If the variable x is anything less than 512, some error has occurred.

8. What is the difference between goto and long jmp( ) and setjmp()?

A goto statement implements a local jump of program execution, and the longjmp() and setjmp() functions implement a nonlocal, or far, jump of program execution. Generally, a jump in execution of any kind should be avoided because it is not considered good programming practice to use such statements as goto and longjmpin your program.
A goto statement simply bypasses code in your program and jumps to a predefined position. To use the gotostatement, you give it a labeled position to jump to. This predefined position must be within the same function. You cannot implement gotos between functions. Here is an example of a goto statement:
void bad_programmers_function(void)
{
int x;
printf("Excuse me while I count to 5000...\n");
x = 1;
while (1)
{
printf("%d\n", x);
if (x == 5000)
goto all_done;
else
x = x + 1;
}
all_done:
printf("Whew! That wasn't so bad, was it?\n");
}
This example could have been written much better, avoiding the use of a goto statement. Here is an example of an improved implementation:
void better_function(void)
{
int x;
printf("Excuse me while I count to 5000...\n");
for (x=1; x<=5000; x++)
printf("%d\n", x);
printf("Whew! That wasn't so bad, was it?\n");
}
As previously mentioned, the longjmp() and setjmp() functions implement a nonlocal goto. When your program calls setjmp(), the current state of your program is saved in a structure of type jmp_buf. Later, your program can call the longjmp() function to restore the program's state as it was when you called setjmp(). Unlike the goto statement, the longjmp() and setjmp() functions do not need to be implemented in the same function.
However, there is a major drawback to using these functions: your program, when restored to its previously saved state, will lose its references to any dynamically allocated memory between the longjmp() and thesetjmp(). This means you will waste memory for every malloc() or calloc() you have implemented between your longjmp() and setjmp(), and your program will be horribly inefficient. It is highly recommended that you avoid using functions such as longjmp() and setjmp() because they, like the goto statement, are quite often an indication of poor programming practice.
Here is an example of the longjmp() and setjmp() functions:
#include
#include
jmp_buf saved_state;
void main(void);
void call_longjmp(void);
void main(void)
{
int ret_code;
printf("The current state of the program is being saved...\n");
ret_code = setjmp(saved_state);
if (ret_code == 1)
{
printf("The longjmp function has been called.\n");
printf("The program's previous state has been restored.\n");
exit(0);
}
printf("I am about to call longjmp and\n");
printf("return to the previous program state...\n");
call_longjmp();
}
void call_longjmp(void)
{
longjmp(saved_state, 1);
}

9. What is an lvalue?

An lvalue is an expression to which a value can be assigned. The lvalue expression is located on the left side of an assignment statement, whereas an rvalue is located on the right side of an assignment statement. Each assignment statement must have an lvalue and an rvalue. The lvalue expression must reference a storable variable in memory. It cannot be a constant. For instance, the following lines show a few examples of lvalues:
int x;
int* p_int;
x = 1;
*p_int = 5;
The variable x is an integer, which is a storable location in memory. Therefore, the statement x = 1 qualifies xto be an lvalue. Notice the second assignment statement, *p_int = 5. By using the * modifier to reference the area of memory that p_int points to, *p_int is qualified as an lvalue. In contrast, here are a few examples of what would not be considered lvalues:
#define CONST_VAL 10
int x;
/* example 1 */
1 = x;
/* example 2 */
CONST_VAL = 5;
In both statements, the left side of the statement evaluates to a constant value that cannot be changed because constants do not represent storable locations in memory. Therefore, these two assignment statements do not contain lvalues and will be flagged by your compiler as errors.

10. Can an array be an lvalue?

Is an array an expression to which we can assign a value? The answer to this question is no, because an array is composed of several separate array elements that cannot be treated as a whole for assignment purposes. The following statement is therefore illegal:
int x[5], y[5];
x = y;
You could, however, use a for loop to iterate through each element of the array and assign values individually, such as in this example:
int i;
int x[5];
int y[5];
...
for (i=0; i<5; i++)
x[i] = y[i]
...
Additionally, you might want to copy the whole array all at once. You can do so using a library function such as the memcpy() function, which is shown here:
memcpy(x, y, sizeof(y));
It should be noted here that unlike arrays, structures can be treated as lvalues. Thus, you can assign one structure variable to another structure variable of the same type, such as this:
typedef struct t_name
{
char last_name[25];
char first_name[15];
char middle_init[2];
} NAME;
...
NAME my_name, your_name;
...
your_name = my_name;
...
In the preceding example, the entire contents of the my_name structure were copied into the your_namestructure. This is essentially the same as the following line:
memcpy(your_name, my_name, sizeof(your_name));




Partner Sites
LucentBlackBoard.com                  SoftLucent.com                  LucentJobs.com
All rights reserved © 2012-2015 SoftLucent.